package com.small.sentinel.slots.block.degrade;

import com.small.common.core.collection.CollectionUtil;
import com.small.common.core.spi.Spi;
import com.small.common.designPattern.behavioral.chainOfResponsibility.slotchain.AbstractLinkedProcessorSlot;
import com.small.sentinel.Constants;
import com.small.sentinel.Context;
import com.small.sentinel.Entry;
import com.small.sentinel.slotchain.ResourceWrapper;
import com.small.sentinel.slots.SentinelResource;
import com.small.sentinel.slots.block.BlockException;
import com.small.sentinel.slots.block.degrade.circuitbreaker.CircuitBreaker;

import java.util.List;

@Spi(order = Constants.ORDER_DEGRADE_SLOT)
public class DegradeSlot extends AbstractLinkedProcessorSlot<SentinelResource> {

    @Override
    public void entry(SentinelResource resource) throws Throwable {
        performChecking(resource.getContext(), resource.getResourceWrapper());
        fireEntry(resource);
    }

    @Override
    public void exit(SentinelResource resource) throws Throwable {
        Entry curEntry = resource.getContext().getCurEntry();
        //发生限流异常进行
        if (curEntry == null || curEntry.getBlockError() != null){
            fireExit(resource);
            return;
        }
        List<CircuitBreaker> circuitBreakers = DegradeRuleManager.getCircuitBreakers(resource.getResourceWrapper().getName());
        if (CollectionUtil.isEmpty(circuitBreakers)){
            fireExit(resource);
            return;
        }
        for (CircuitBreaker circuitBreaker : circuitBreakers) {
            circuitBreaker.onRequestComplete(resource.getContext());
        }
        fireExit(resource);
    }
    
    private void performChecking(Context context, ResourceWrapper resourceWrapper) throws BlockException {

        List<CircuitBreaker> circuitBreakers = DegradeRuleManager.getCircuitBreakers(resourceWrapper.getName());

        if (CollectionUtil.isEmpty(circuitBreakers)){
            return;
        }
        for (CircuitBreaker cb : circuitBreakers) {
            if (!cb.tryPass(context)) {
                throw new DegradeException(cb.getRule().getLimitApp(), cb.getRule());
            }
        }

    }
}
